package org.victoria.common.dao.imp;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.victoria.common.annotation.UpdateField;
import org.victoria.common.config.Constant;
import org.victoria.common.dao.DaoSupport;
import org.victoria.common.domain.Page;
import org.victoria.common.exception.UpdateFailureException;
import org.victoria.common.utils.QueryHelper;

import javax.annotation.Resource;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by Administrator on 14-8-17.
 */
public abstract class DaoSupportImp<T> implements DaoSupport<T> {

    @Resource
    private SessionFactory sessionFactory;

    private Logger logger = LoggerFactory.getLogger(DaoSupportImp.class);
    private Class<T> clazz;
    public DaoSupportImp<T> dao = this;

    public DaoSupportImp() {
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        this.clazz = (Class<T>) type.getActualTypeArguments()[0];
    }

    /**
     * Session
     * @return
     */
    public Session getSession(){
        return sessionFactory.getCurrentSession();
    }

    /**
     * 获得查询数据的HQL辅助类
     * @return
     */
    public QueryHelper getSelectHelper(){
        return new QueryHelper(clazz, QueryHelper.HelperEnum.SELECT);
    }

    /**
     * 获得更新数据的HQL辅助类
     * @return
     */
    public QueryHelper getUpdateHelper(){
        return new QueryHelper(clazz, QueryHelper.HelperEnum.UPDATE);
    }

    /**
     * 获得可以自定义SQL的辅助类
     * @return
     */
    public QueryHelper getSimpleHelper(){
        return new QueryHelper(clazz);
    }

    /**
     * 保存对象
     * @param t
     */
    @Override
    public void save(T t) {
        getSession().save(t);
    }

    /**
     * 完全更新对象
     * @param t
     */
    @Override
    @Deprecated
    public void update(T t) {
        getSession().update(t);
    }

    /**
     * 根据条件更新对象
     * @param helper
     */
    @Override
    public void update(QueryHelper helper) {
        List<Object> params = helper.getParams();
        Query query = helper.getQuery(getSession());
        if (params != null && params.size() > 0){
            for (int i = 0; i < params.size(); i++){
                query.setParameter(i, params.get(i));
            }
        }
        query.executeUpdate();
    }

    /**
     * 更新指定注解上的匹配名称空间的字段，注意！它只适用于使用注解映射实体的情况
     * @param object 带有值的实例对象
     */
    public void update(T object, String namespace){
        try {
            QueryHelper helper = getUpdateHelper();
            ArrayList<Field> fields = new ArrayList<Field>();
            for (Class c = object.getClass(); c != Object.class; c = c.getSuperclass()){
                if (c.getAnnotation(Entity.class)!=null || c.getAnnotation(MappedSuperclass.class)!=null){
                    Field[] fs = c.getDeclaredFields();
                    fields.addAll(Arrays.asList(fs));
                }
            }
            for (Field field : fields) {
                String dataType = field.getType().getName();
                if (Constant.getDataTypeMap().get(dataType) != null) {
                    char[] chars = field.getName().toCharArray();
                    chars[0] -= 32;
                    String str_method = "get" + new String(chars);
                    Method method = clazz.getMethod(str_method, null);
                    UpdateField a = field.getAnnotation(UpdateField.class)==null
                            ? method.getAnnotation(UpdateField.class)
                            : field.getAnnotation(UpdateField.class);
                    if (a != null){
                        String[] namespaces = a.namespace();
                        if (namespaces!=null && namespaces.length>0){
                            for (String ns : namespaces){
                                if (ns.equals(namespace)){
                                    Object arg = method.invoke(object, null);
                                    helper.set(field.getName(), arg);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            Method method = clazz.getMethod("getId", null);
            Object id_obj = method.invoke(object, null);
            if (id_obj != null){
                helper.where("id", id_obj);
                update(helper);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new UpdateFailureException();
        }
    }

    /**
     * 根据id获取对象
     * @param id
     * @return
     */
    @Override
    public T getById(Serializable id) {
        if (id==null)
            return null;
        return (T) getSession().load(clazz, id);
}

    /**
     * 查找对象，得到一个集合
     * @param helper 辅助类
     * @param cacheable 是否缓存
     * @return
     */
    @Override
    public List<T> find(QueryHelper helper, boolean cacheable) {
        List<Object> params = helper.getParams();
        Query query = helper.getQuery(getSession());
        if (params != null && params.size() > 0){
            for (int i = 0; i < params.size(); i++){
                query.setParameter(i, params.get(i));
            }
        }
        query.setCacheable(cacheable);
        return query.list();
    }

    /**
     * 查找对象，得到单个对象
     * @param helper
     * @param cacheable 是否缓存
     * @return
     */
    @Override
    public T findUnique(QueryHelper helper, boolean cacheable) {
        List<Object> params = helper.getParams();
        Query query = helper.getQuery(getSession());
        if (params != null && params.size() > 0){
            for (int i = 0; i < params.size(); i++){
                query.setParameter(i, params.get(i));
            }
        }
        query.setCacheable(cacheable);
        return (T) query.uniqueResult();
    }

    @Override
    public List<T> findAll(boolean cacheable) {
        Query query = getSession().createQuery("FROM "+clazz.getSimpleName());
        query.setCacheable(cacheable);
        return query.list();
    }

    /**
     * 彻底删除
     * @param id
     */
    @Override
    public void absoluteDelete(Serializable id) {
        getSession().createSQLQuery("DELETE FROM "+clazz.getSimpleName()+" WHERE id = ?")
                .setParameter(0, id)
                .executeUpdate();
    }

    /**
     * 分页
     * @param pageNum
     * @param helper
     * @param pageSize
     * @return
     */
    @Override
    public Page<T> getPage(int pageNum, QueryHelper helper, int pageSize) {
        List<T> list = this.getSinglePage(pageNum, helper, pageSize, true);
        int count = getCount(helper, false);
        return new Page<T>(pageNum, pageSize, count, list);
    }

    /**
     *
     * @param pageNum
     * @param helper
     * @param pageSize
     * @return
     */
    @Override
    public List<T> getSinglePage(int pageNum, QueryHelper helper, int pageSize, boolean cacheable) {
        //查询分页数据
        List<Object> params = helper.getParams();
        Query query = helper.getQuery(getSession());
        if (params != null && params.size() > 0){
            for (int i = 0; i < params.size(); i++){
                query.setParameter(i, params.get(i));
            }
        }
        query.setFirstResult((pageNum - 1) * pageSize);
        query.setMaxResults(pageSize);
        query.setCacheable(cacheable);
        return query.list();
    }

    /**
     * 自动减一
     * 已过时，见void autoUpOrDown(Serializable id, String clause, boolean up)
     * @param id
     * @param clause
     */
    @Override
    @Deprecated
    public void autoDecrease(Serializable id, String clause) {
        getSession().createQuery("UPDATE "+clazz.getSimpleName()+" SET "+clause+"="+clause+"-1 WHERE id=?")
                .setParameter(0, id)
                .executeUpdate();
    }

    /**
     * @param id 对象id
     * @param clause 指定操作的列
     * @param up 如果为true，则自增1，如果为false，则自减1
     */
    @Override
    public void autoUpOrDown(Serializable id, String clause, boolean up) {
        System.out.println(""+(up?"":""));
        getSession().createQuery("UPDATE "+clazz.getSimpleName()+" SET "+clause+"="+clause+(up?"+":"-")+"1 WHERE id=?")
                .setParameter(0, id)
                .executeUpdate();
    }

    /**
     * 得到总记录数，如果没有记录，返回0
     * @param helper
     * @param cacheable 是否缓存
     * @return
     */
    @Override
    public int getCount(QueryHelper helper, boolean cacheable) {
        List<Object> params = helper.getParams();
        logger.debug("getCount--->"+helper.getQueryCountHql());
        Query query = helper.getCountSQLQuery(getSession());
        if (params != null && params.size() > 0){
            for (int i = 0; i < params.size(); i++){
                query.setParameter(i, params.get(i));
            }
        }
        query.setCacheable(cacheable);
        Long count = Long.valueOf(query.uniqueResult().toString());
        return count==null ? 0 : count.intValue();
    }

    @Override
    public void delete(Long id) {
        getSession().delete(getById(id));
    }

    @Override
    public Page<T> getPage(int pageNum, QueryHelper helper, int pageSize, boolean cacheable) {
        List<T> list = this.getSinglePage(pageNum, helper, pageSize, cacheable);
        int count = getCount(helper, false);
        return new Page<T>(pageNum, pageSize, count, list);
    }
}
